<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      class Event {
        constructor() {
          this.cache = {};
        }

        on(name, fn) {
          if (this.cache[name]) {
            this.cache[name].push(fn);
          } else {
            this.cache[name] = [fn];
          }
        }

        // off(name, fn) {
        //   let tasks = this.cache[name];
        //   if (tasks) {
        //     let index = tasks.findIndex((f) => f === fn || f.callback === fn);
        //     if (index >= 0) {
        //       tasks.splice(index, 1);
        //     }
        //     这种方式的另一种写法（目前还没测试）
        //     tasks = tasks.filter((cb) => fn !== cb)
        //   }
        // }

        // 自己理解的版本
        off(name) {
          if (this.cache[name]) {
            delete this.cache[name];
          } else {
            // 不传值就是全部解除
            this.cache = {};
          }
        }

        emit(name, once = false, ...args) {
          if (this.cache[name]) {
            // 创建副本,如果回调函数内继续注册相同事件,会造成死循环
            let tasks = this.cache[name].slice();
            for (let fn of tasks) {
              fn(...args);
            }
            if (once) {
              delete this.cache[name];
            }
          }
        }
      }

      let eventBus = new Event();
      let fn1 = function (name, age) {
        console.log(`${name} ${age}`);
      };

      // 上面自己理解的方式的输出
      eventBus.on("aaa", fn1);
      eventBus.on("bbb", fn1);
      eventBus.on("ccc", fn1);
      eventBus.emit("aaa", false, "quan", 23);
      eventBus.off('aaa');
      eventBus.emit("aaa", false, "light", 24);
      eventBus.emit("bbb", false, "huan", 24);
      eventBus.emit("ccc", true, "ding", 24);
      eventBus.emit("ccc", true, "ding", 24);

      // 别人一开始写的那种方式的输出
      // eventBus.on("aaa", fn1);
      // eventBus.on("aaa", fn1);
      // eventBus.emit("aaa", false, "quan", 23);  //输出两次
      // eventBus.off('aaa');
      // eventBus.emit("aaa", false, "quan", 23);  //输出一次，因为注销了一次
    </script>
  </body>
</html>
